﻿using System;
using System.IO;
using System.Web;

namespace Nana.Web.Compressing
{
  public class ResponseCompressFilter : Stream
  {
    private Stream filter = null;

    /// <summary>
    /// 最终接受写入数据的基础流。
    /// </summary>
    public Stream BaseFilter { get; private set; }

    /// <summary>
    /// 关联的 HttpContext。
    /// </summary>
    public HttpContext Context { get; private set; }

    public ResponseCompressFilter(HttpContext context)
      : this(context, context.Response.Filter)
    { }
    public ResponseCompressFilter(HttpContext context, Stream baseFilter)
    {
      BaseFilter = baseFilter;
      Context = context;
    }

    /// <summary>
    /// 关闭所有依赖的资源。
    /// </summary>
    public override void Close()
    {
      try
      {
        OperatingStream.Close();
      }
      finally
      {
        filter = null;
        BaseFilter = null;
        base.Close();
      }
    }

    [System.Diagnostics.Conditional("DEBUG")]
    void WriteDebugHeader()
    {
      Context.Response.AppendHeader("X-Debug-Compression-Cache-Id", CompressionModule.eventChoice + ":" + Guid.NewGuid().ToString()
        + ":" + CompressionModule.dynamicFilterList.Count + "," + CompressionModule.staticFilterList.Count
      );
    }

    /// <summary>
    /// 用于执行写入操作的流对象。
    /// </summary>
    private Stream OperatingStream
    {
      get
      {
        // 由于最终的内容类型是由 IHttpHandler 决定的，所以在开始写入的时候才判断是不是要进行压缩
        // 为了便于维护，这个判断并不直接在 Write 的 override 中实现，而是做成一个私有属性，当此属性被 Write 的 override 访问时进行判断
        if (null == filter)
        {
          WriteDebugHeader();

          // 不知道该使用何种压缩方式？让专业的来！
          var factory = Context.PickCompressFilterFactory();


          if (null == factory)
          {
            // 既然没有合适的就直接使用基础流
            filter = BaseFilter;
          }
          else
          {
            // 写入对应的 HTTP 以告知浏览器所采用的编码方式
            factory.SetupHeaders(Context);
            // 具体的压缩过滤器是由其 factory 来创建的
            filter = factory.CreateFilter(BaseFilter);
          }
        }
        return filter;
      }
    }

    #region
    public override bool CanRead
    {
      get { return false; }
    }
    public override bool CanSeek
    {
      get { return false; }
    }
    #endregion

    public override bool CanWrite
    {
      get
      {
        // 直接反映 OperatingStream 的状态
        return OperatingStream.CanWrite;
      }
    }
    public override void Flush()
    {
      OperatingStream.Flush();
    }

    #region
    public override long Length
    {
      get { throw new NotSupportedException(); }
    }
    public override long Position
    {
      get { throw new NotSupportedException(); }
      set { throw new NotSupportedException(); }
    }
    public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
    public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
    public override void SetLength(long value) { throw new NotSupportedException(); }
    #endregion

    public override void Write(byte[] buffer, int offset, int count)
    {
      // 不管 OperatingStream 到底是什么，向里边写准没错
      OperatingStream.Write(buffer, offset, count);
    }

  }
}
